<!--
 * hi-tabs - 选项卡
 *
 * @author 济南晨霜信息技术有限公司
 * @mobile 18560000860 / 18754137913
 -->
<template>
    <view class="hi-tabs" :class="_classes" :style="_styles">
        <!-- Left -->
        <view class="hi-tabs__left">
            <scroll-view
                class="hi-tabs__scroll"
                id="hiTabsScrollView"
                :scroll-x="!column"
                :scroll-y="!!column"
                :scroll-top="scrollTop"
                :scroll-left="scrollLeft"
                :scroll-with-animation="scrollWithAnimation"
                @scroll="onScroll"
            >
                <view class="hi-tabs__scroll-content">
                    <view class="hi-tabs__items" id="hiTabsItems">
                        <view
                            class="hi-tabs__item hi-tabs__item--left"
                            v-for="(_item, _index) in list"
                            :key="_index"
                            :class="{ 'hi-tabs__item--active': _index === current, 'hi-tabs__item--disabled hi-disabled': _item?.disabled }"
                            :hover-class="hover"
                            @tap="handleItemClick(_item, _index)"
                            :id="`hiTabsItem${_index}`"
                            :style="_index === current ? activeStyles : styles"
                        >
                            <slot name="item" :item="_item" :index="_index">
                                <hi-icon class="hi-tabs__item__icon hi-tabs__item__icon--left" :name="_item?.icon" v-if="_item?.icon"></hi-icon>
                                <view class="hi-tabs__item__text hi-tabs__item__text--left" v-if="_item?.[keyName]">{{ _item[keyName] }}</view>
                            </slot>
                        </view>
                    </view>
                </view>
            </scroll-view>
        </view>

        <!-- Right -->
        <view class="hi-tabs__right" v-if="right?.length">
            <slot name="right">
                <slot name="rightItem">
                    <view
                        class="hi-tabs__item hi-tabs__item--right"
                        :hover-class="hover"
                        v-for="(_item, _index) in right"
                        :key="_index"
                        :class="{ 'hi-disabled': _item?.disabled }"
                        @tap="_emits('rightClick', _item, _index)"
                    >
                        <hi-icon class="hi-tabs__item__icon hi-tabs__item__icon--right" :name="_item?.icon" v-if="_item.icon"></hi-icon>
                        <view class="hi-tabs__item__text hi-tabs__item__text--right" v-if="_item?.[keyName]">{{ _item[keyName] }}</view>
                    </view>
                </slot>
            </slot>
        </view>
    </view>
</template>

<!-- 由于 HbuilderX 不支持 defineOptions() 写法，故只能在此处进行配置 -->
<script>
    export default { options: uni?.$hi?.config?.componentsOptions || {} };
</script>

<script setup>
    import { ref, computed, onMounted, getCurrentInstance, watch, nextTick } from "vue";
    import props from "./props.js";
    import { uniGetNodeRectInfo, sleep } from "../../functions";

    // 组件实例
    const instance = getCurrentInstance();

    // 组件属性
    const _props = defineProps(props);

    // 组件事件
    const _emits = defineEmits(["change", "rightClick", "itemClick"]);

    // 组件类名
    const _classes = computed(() => {
        const classes = [];

        // 是否纵向布局
        if (_props.column) classes.push(`hi-tabs--column`);

        // 等分布局
        if (_props.equal) classes.push(`hi-tabs--equal`);

        // 两端对齐
        if (_props.justify) classes.push(`hi-tabs--justify`);

        return classes;
    });

    // 组件样式
    const _styles = computed(() => {
        const styles = [];

        // 背景
        if (_props.bg) styles.push(`--hi-tabs-background: ${_props.bg};`);

        // 圆角
        if (_props.radius) styles.push(`--hi-tabs-border-radius: ${_props.radius};`);

        // 宽
        if (_props.width) styles.push(`--hi-tabs-width: ${_props.width};`);

        // 高
        if (_props.height) styles.push(`--hi-tabs-height: ${_props.height};`);

        // 文字颜色
        if (_props.color) styles.push(`--hi-tabs-color: ${_props.color};`);

        // 文字大小
        if (_props.fontSize) styles.push(`--hi-tabs-font-size: ${_props.fontSize};`);

        // 文字粗细
        if (_props.fontWeight) styles.push(`--hi-tabs-font-weight: ${_props.fontWeight};`);

        // 激活项文字颜色
        if (_props.activeColor) styles.push(`--hi-tabs-active-color: ${_props.activeColor};`);

        // 激活项文字大小
        if (_props.activeFontSize) styles.push(`--hi-tabs-active-font-size: ${_props.activeFontSize};`);

        // 激活项文字粗细
        if (_props.activeFontWeight) styles.push(`--hi-tabs-active-font-weight: ${_props.activeFontWeight};`);

        // 指示器宽度
        if (_props.barWidth) styles.push(`--hi-tabs-bar-width: ${_props.barWidth};`);

        // 指示器高度
        if (_props.barHeight) styles.push(`--hi-tabs-bar-height: ${_props.barHeight};`);

        // 指示器圆角
        if (_props.barRadius) styles.push(`--hi-tabs-bar-border-radius: ${_props.barRadius};`);

        // 指示器颜色
        if (_props.barColor) styles.push(`--hi-tabs-bar-background: ${_props.barColor};`);

        // 指示器的位置
        if (_props.barLeft) styles.push(`--hi-tabs-bar-left: ${_props.barLeft};`);
        if (_props.barBottom) styles.push(`--hi-tabs-bar-bottom: ${_props.barBottom};`);

        // 选项之间的间距
        if (_props.gap) styles.push(`--hi-tabs-items-gap: ${_props.gap};`);

        // 选项内边距
        if (_props.itemPadding) styles.push(`--hi-tabs-item-padding: ${_props.itemPadding};`);

        // 图标颜色
        if (_props.iconColor) styles.push(`--hi-tabs-item-icon-color: ${_props.iconColor};`);

        // 图标大小
        if (_props.iconSize) styles.push(`--hi-tabs-item-icon-font-size: ${_props.iconSize};`);

        // 激活的图标颜色
        if (_props.activeIconColor) styles.push(`--hi-tabs-item-active-icon-color: ${_props.activeIconColor};`);

        // 激活的图标大小
        if (_props.activeIconSize) styles.push(`--hi-tabs-item-active-icon-font-size: ${_props.activeIconSize};`);

        // 选项背景
        if (_props.itemBg) styles.push(`--hi-tabs-item-background: ${_props.itemBg};`);

        // 激活项背景
        if (_props.activeItemBg) styles.push(`--hi-tabs-item-active-background: ${_props.activeItemBg};`);

        return styles;
    });

    // 滚动容器布局信息
    const _scrollViewRectInfo = ref(null);

    // items 容器布局信息
    const _itemsConrainerRectInfo = ref(null);

    // 滚动距离
    const scrollTop = ref(0);
    const scrollLeft = ref(0);

    // 最小可滚动距离
    const minScroll = ref(0);

    // 最大可滚动距离
    const maxScroll = computed(() => {
        // 横向布局
        if (!_props.column) return (_itemsConrainerRectInfo.value?.width || 0) - (_scrollViewRectInfo.value?.width || 0);

        // 纵向布局
        return (_itemsConrainerRectInfo.value?.height || 0) - (_scrollViewRectInfo.value?.height || 0);
    });

    // 是否正在滚动
    const isScrolling = ref(false);
    let scrollTimer = null; // 用于更新滚动状态

    // 监听下标和 items 数据变化后自动滚动
    const watchValues = computed(() => [_props.current, _props.list]);
    watch(watchValues, async () => {
        // 等分时，默认不滚动，所以无需自动滚动
        if (_props.equal) return;

        // 两端对齐时，无需自动滚动
        if (_props.justify) return;

        // 未开启自动滚动，也无需自动滚动
        if (!_props.autoScroll) return;

        // 等数据渲染完成后，再进行滚动
        await nextTick();

        // 稍微那么等待一下，虽然在 H5 测试的不等待也可以，但是以防万一
        await sleep(100);

        // 自动滚动
        scrollItemToCenter();
    });

    // 组件渲染完成后
    onMounted(async () => {
        // 等分时，默认不滚动，所以无需获取布局信息，节省点性能
        if (_props.equal) return;

        // 两端对齐时，无需获取布局信息，节省点性能
        if (_props.justify) return;

        // 未开启自动滚动时，也无需获取布局信息
        if (!_props.autoScroll) return;

        // 获取 items 容器布局信息
        await getItemsRectInfo();

        // #ifdef MP-TOUTIAO
        await sleep(100);
        // #endif

        // 自动滚动
        scrollItemToCenter();
    });

    // 滚动
    function onScroll(event) {
        scrollTop.value = event.detail.scrollTop;
        scrollLeft.value = event.detail.scrollLeft;
        isScrolling.value = true;
        if (scrollTimer) {
            clearInterval(scrollTimer);
            scrollTimer = null;
        }
        scrollTimer = setTimeout(() => {
            isScrolling.value = false;
            clearInterval(scrollTimer);
            scrollTimer = null;
        }, 200);
    }

    // 获取容器布局信息
    function getSrollViewRectInfo() {
        return uniGetNodeRectInfo("#hiTabsScrollView", instance).then((res) => {
            if (res) {
                // 添加中心点信息
                // 横向布局
                if (!_props.column) res.center = res.left + res.width / 2;
                // 纵向布局
                else res.center = res.top + res.height / 2;

                // 更新布局信息数据
                _scrollViewRectInfo.value = res;
            }
        });
    }

    // 获取 items 容器布局信息
    function getItemsRectInfo() {
        return uniGetNodeRectInfo("#hiTabsItems", instance).then((res) => {
            if (res) {
                // 更新布局信息数据
                _itemsConrainerRectInfo.value = res;
            }
        });
    }

    // 滚动元素到中心点
    async function scrollItemToCenter() {
        // 获取滚动容器布局信息
        // 因为页面滚动后布局信息会变化，所以需要再滚动时实施获取最新的布局信息
        await getSrollViewRectInfo();

        // 目标 item 的 id
        const itemId = `hiTabsItem${_props.current}`;

        // 获取目标 item 的布局信息
        uniGetNodeRectInfo(`#${itemId}`, instance).then((res) => {
            if (res) {
                // 元素 item 的中心点坐标
                // 横向布局
                if (!_props.column) res.center = res.left + res.width / 2;
                // 纵向布局
                else res.center = res.top + res.height / 2;

                // 确保正确获取到了相关元素的布局信息，避免控制台报错
                if (_scrollViewRectInfo.value && _itemsConrainerRectInfo.value) {
                    // 移动距离
                    const move = res.center - _scrollViewRectInfo.value.center;

                    // 向左/上滚动
                    if (move > 0) {
                        // 横向布局
                        if (!_props.column) {
                            scrollLeft.value = scrollLeft.value + move > maxScroll.value ? maxScroll.value : scrollLeft.value + move;
                        }

                        // 纵向布局
                        else {
                            scrollTop.value = scrollTop.value + move > maxScroll.value ? maxScroll.value : scrollTop.value + move;
                        }
                    }

                    // 向右/下滚动
                    else if (move < 0) {
                        // 横向布局
                        if (!_props.column) {
                            scrollLeft.value = scrollLeft.value + move < minScroll.value ? minScroll.value : scrollLeft.value + move;
                        }

                        // 纵向布局
                        else {
                            scrollTop.value = scrollTop.value + move < minScroll.value ? minScroll.value : scrollTop.value + move;
                        }
                    }
                }
            }
        });
    }

    // 点击事件
    function handleItemClick(item, index) {
        _emits("itemClick", item, index);

        // 禁用
        if (item?.disabled) return;

        // 点击的是激活的元素
        if (_props.current === index) return;

        // 切换
        _emits("change", item, index);
    }
</script>

<style lang="scss" scoped>
    .hi-tabs {
        background: var(--hi-tabs-background, none);
        border-radius: var(--hi-tabs-border-radius, 0);
        display: var(--hi-tabs-display, flex);
        flex-direction: var(--hi-tabs-flex-direction, row);
        align-items: var(--hi-tabs-align-items, stretch);
        gap: var(--hi-tabs-gap, 0);
        width: var(--hi-tabs-width, 100%);
        height: var(--hi-tabs-height, 3em);
        text-align: var(--hi-tabs-text-align, center);
        color: var(--hi-tabs-color, inherit);
        font-size: var(--hi-tabs-font-size, inherit);
        font-weight: var(--hi-tabs-font-weight, inherit);

        &__left {
            flex: var(--hi-tabs-left-flex, 1);
            overflow: var(--hi-tabs-left-overflow, hidden);
            position: var(--hi-tabs-left-position, relative);
        }

        &__scroll {
            white-space: nowrap;
            height: 100%;

            &::-webkit-scrollbar,
            ::-webkit-scrollbar {
                display: none;
            }
        }

        &__scroll-content {
            height: 100%;
            display: flex;
            flex-wrap: nowrap;
            white-space: nowrap;
        }

        &__items {
            display: var(--hi-tabs-items-display, flex);
            gap: var(--hi-tabs-items-gap, 15px);
            height: 100%;
            flex-wrap: nowrap;
            white-space: nowrap;
            flex-direction: var(--hi-tabs-items-flex-direction, row);
            justify-content: var(--hi-tabs-items-justify-content, flex-start);
        }

        &__item {
            gap: var(--hi-tabs-item-gap, 2px);
            position: var(--hi-tabs-item-position, relative);
            display: var(--hi-tabs-item-display, flex);
            flex-direction: var(--hi-tabs-item-flex-direction, row);
            align-items: var(--hi-tabs-item-align-items, center);
            justify-content: var(--hi-tabs-item-justify-content, center);
            transition: var(--hi-tabs-item-transition, 100ms);
            flex-shrink: var(--hi-tabs-item-flex-shrink, 0);
            background: var(--hi-tabs-item-background, none);
            padding: var(--hi-tabs-item-padding, 0 5px);
            flex: var(--hi-tabs-item-flex, none);
            width: var(--hi-tabs-item-width, auto);

            &__icon,
            &__text {
                position: relative;
                z-index: 5;
            }

            &__icon {
                color: var(--hi-tabs-item-icon-color, inherit);
                font-size: var(--hi-tabs-item-icon-font-size, 1.25em);
            }

            &::before {
                content: "";
                position: absolute;
                width: 100%;
                height: 100%;
                left: 0;
                top: 0;
                z-index: 0;
                background: var(--hi-tabs-item-active-background, var(--hi-tabs-item-background, currentColor));
                opacity: var(--hi-tabs-item-background-opacity, 0);
                color: inherit;
                transition: inherit;
            }

            &::after {
                content: "";
                width: var(--hi-tabs-bar-width, 1em);
                height: var(--hi-tabs-bar-height, 3px);
                position: absolute;
                color: inherit;
                background: var(--hi-tabs-bar-background, currentColor);
                opacity: var(--hi-tabs-bar-opacity, 0);
                border-radius: var(--hi-tabs-bar-border-radius, 10px);
                transition: inherit;
                left: var(--hi-tabs-bar-left, 50%);
                bottom: var(--hi-tabs-bar-bottom, 1px);
                z-index: 8;
                transform: var(--hi-tabs-bar-transform, translateX(-50%) scale(0));
            }

            &--active {
                color: var(--hi-tabs-active-color, var(--hi-theme-primary));
                font-size: var(--hi-tabs-active-font-size);
                font-weight: var(--hi-tabs-active-font-weight);

                .hi-tabs__item__icon {
                    font-size: var(--hi-tabs-item-active-icon-font-size);
                    color: var(--hi-tabs-item-active-icon-color);
                }

                &::after {
                    transform: var(--hi-tabs-bar-transform, translateX(-50%) scale(1));
                    opacity: var(--hi-tabs-bar-opacity, 1);
                }
            }
        }

        &__right {
            flex-shrink: var(--hi-tabs-right-flex-shrink, 0);
            display: var(--hi-tabs-right-display, flex);
            align-items: var(--hi-tabs-right-align-items, center);
            font-size: var(--hi-tabs-right-font-size, inherit);
            font-weight: var(--hi-tabs-right-font-weight, inherit);
            color: var(--hi-tabs-right-color, inherit);
            gap: var(--hi-tabs-right-gap, 10px);
        }

        &--column {
            flex-direction: var(--hi-tabs-flex-direction, column);
            width: var(--hi-tabs-width, 8em);
            height: var(--hi-tabs-height, 100%);

            .hi-tabs__scroll-content {
                height: auto;
            }

            .hi-tabs__items {
                flex-direction: var(--hi-tabs-items-flex-direction, column);
                height: auto;
                white-space: normal;
                width: 100%;
            }

            .hi-tabs__item {
                padding: var(--hi-tabs-item-padding, 10px);

                &::after {
                    left: var(--hi-tabs-item-bar-left, 1px);
                    bottom: var(--hi-tabs-item-bar-bottom, 50%);
                    transform: var(--hi-tabs-item-bar-transform, translateY(50%) scale(1));
                    width: var(--hi-tabs-item-bar-width, 3px);
                    height: var(--hi-tabs-item-bar-height, 1em);
                }

                &--active::before {
                    opacity: var(--hi-tabs-item-background-opacity, 0.2);
                }
            }
        }

        &--justify {
            .hi-tabs__scroll-content {
                white-space: normal;
            }

            .hi-tabs__items {
                width: 100%;
                white-space: normal;
                justify-content: var(--hi-tabs-items-justify-content, space-between);
            }
        }

        &--equal {
            .hi-tabs__scroll-content {
                white-space: normal;
                width: 100%;
            }

            .hi-tabs__items {
                width: 100%;
                white-space: normal;
                justify-content: var(--hi-tabs-items-justify-content, space-between);
            }

            .hi-tabs__item {
                flex: var(--hi-tabs-item-flex, 1);
            }
        }
    }
</style>
